from flask import Flask, render_template, jsonify, request, redirect, url_for, flash, session, get_flashed_messages
from flasgger import Swagger
from models import db, GroupInfo, TeamMember, User
import database
import os
from functools import wraps
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash

# 初始化Flask应用
app = Flask(__name__)
app.secret_key = 'your_secret_key_here'  # 用于session和flash消息，生产环境请更换为安全随机值

# 初始化Swagger
swagger = Swagger(app)

# 确保instance文件夹存在
os.makedirs(app.instance_path, exist_ok=True)

# 配置数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.instance_path, 'group_info.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 文件上传配置
app.config['UPLOAD_FOLDER'] = 'static/avatars'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max file size
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

# 确保头像上传目录存在
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

db.init_app(app)

# 创建数据库表
with app.app_context():
    db.create_all()

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'username' not in session:
            flash('请先登录', 'warning')
            return redirect(url_for('auth'))
        return f(*args, **kwargs)
    return decorated_function

# 首页路由
@app.route('/')
def index():
    return render_template('index.html')

# 登录/注册合并页面
@app.route('/auth', methods=['GET', 'POST'])
def auth():
    # 清除之前的闪存消息
    session.pop('_flashes', None)

    # 判断是登录还是注册表单提交
    if request.method == 'POST':
        if request.form.get('confirm_password') is not None:
            # 注册
            username = request.form.get('username')
            password = request.form.get('password')
            confirm_password = request.form.get('confirm_password')
            if not username or not password or not confirm_password:
                flash('请填写所有字段', 'danger')
            elif password != confirm_password:
                flash('两次密码不一致', 'danger')
            else:
                # 处理头像上传
                avatar_filename = 'default_avatar.png'
                if 'avatar' in request.files:
                    file = request.files['avatar']
                    if file and file.filename != '' and allowed_file(file.filename):
                        filename = secure_filename(file.filename)
                        file_ext = filename.rsplit('.', 1)[1].lower()
                        avatar_filename = f"{username}.{file_ext}"
                        file_path = os.path.join(app.config['UPLOAD_FOLDER'], avatar_filename)
                        file.save(file_path)
                
                # 创建用户
                try:
                    hashed_password = generate_password_hash(password)
                    new_user = User(username=username, password=hashed_password, avatar=avatar_filename)
                    db.session.add(new_user)
                    db.session.commit()
                    flash('注册成功，请登录', 'success')
                except Exception as e:
                    db.session.rollback()
                    flash('用户名已存在', 'danger')
        else:
            # 登录
            username = request.form.get('username')
            password = request.form.get('password')
            if not username or not password:
                flash('请填写所有字段', 'danger')
            elif database.check_user(username, password):
                session['username'] = username
                flash('登录成功', 'success')
                return redirect(url_for('index'))
            else:
                flash('用户名或密码错误', 'danger')
    return render_template('auth.html', messages=get_flashed_messages(with_categories=True))

@app.route('/logout')
def logout():
    session.pop('username', None)
    flash('已退出登录', 'info')
    return redirect(url_for('index'))

@app.route('/upload_avatar', methods=['POST'])
@login_required
def upload_avatar():
    if 'avatar' not in request.files:
        return jsonify({'error': '没有选择文件'}), 400
    
    file = request.files['avatar']
    if file.filename == '':
        return jsonify({'error': '没有选择文件'}), 400
    
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        # 使用用户名作为文件名，避免冲突
        username = session['username']
        file_ext = filename.rsplit('.', 1)[1].lower()
        new_filename = f"{username}.{file_ext}"
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
        
        file.save(file_path)
        
        # 更新数据库中的头像路径
        user = User.query.filter_by(username=username).first()
        if user:
            user.avatar = new_filename
            db.session.commit()
        
        return jsonify({'success': True, 'avatar': new_filename})
    
    return jsonify({'error': '不支持的文件格式'}), 400

@app.route('/get_user_info')
def get_user_info():
    if 'username' in session:
        user = User.query.filter_by(username=session['username']).first()
        if user:
            return jsonify({
                'username': user.username,
                'avatar': user.avatar
            })
    return jsonify({'error': '未登录'}), 401

@app.route('/score')
@login_required
def score():
    return render_template('score.html')

@app.route('/about')
def about():
    return render_template('about.html')

@app.route('/api/teams')
def get_teams():
    """
    获取所有队伍数据
    ---
    tags:
      - Teams
    responses:
      200:
        description: 队伍列表
        schema:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
              score:
                type: integer
    """
    groups = GroupInfo.query.all()
    teams = [{'id': group.id, 'name': group.name, 'score': group.count} for group in groups]
    return jsonify(teams)

@app.route('/api/update-scores', methods=['POST'])
def update_scores():
    try:
        teams = request.json
        for team in teams:
            group = GroupInfo.query.get(team['id'])
            if group:
                group.count = team['score']
        db.session.commit()
        return jsonify({"success": True})
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": str(e)}), 500

# 删除队伍API
@app.route('/api/teams/<int:team_id>', methods=['DELETE'])
def delete_team(team_id):
    try:
        group = GroupInfo.query.get(team_id)
        if not group:
            return jsonify({"error": "队伍不存在"}), 404
        db.session.delete(group)
        db.session.commit()
        return jsonify({"success": True})
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": str(e)}), 500

@app.route('/api/add-team', methods=['POST'])
def add_team():
    """
    添加新队伍
    ---
    tags:
      - Teams
    parameters:
      - name: body
        in: body
        required: true
        schema:
          type: object
          required:
            - name
          properties:
            name:
              type: string
              description: 队伍名称
            photo:
              type: string
              description: 队伍照片URL（可选）
    responses:
      201:
        description: 创建成功
        schema:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
            score:
              type: integer
      400:
        description: 队伍名称不能为空
      500:
        description: 服务器错误
    """
    try:
        data = request.json
        if not data or 'name' not in data:
            return jsonify({'error': '队伍名称不能为空'}), 400
        score = data.get('score', 0)
        try:
            score = int(score)
            if score < 0:
                score = 0
        except Exception:
            score = 0
        new_team = GroupInfo(
            name=data['name'],
            count=score
        )
        db.session.add(new_team)
        db.session.commit()
        new_member = TeamMember(
            name=data['name'],
            photo=data.get('photo', ''),
            responsibility='',
            introduction=''
        )
        db.session.add(new_member)
        # 返回新创建的队伍信息
        return jsonify({
            'success': True,
            'id': new_team.id,
            'name': new_team.name,
            'score': new_team.count
        }), 201
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@app.route('/api/teams/<int:team_id>/score', methods=['PUT'])
def update_team_score(team_id):
    """
    更新队伍分数
    ---
    tags:
      - Teams
    parameters:
      - name: team_id
        in: path
        type: integer
        required: true
        description: 队伍ID
      - name: body
        in: body
        required: true
        schema:
          type: object
          required:
            - score
          properties:
            score:
              type: integer
              description: 新分数
    responses:
      200:
        description: 更新成功
        schema:
          type: object
          properties:
            success:
              type: boolean
      400:
        description: 缺少分数数据
      404:
        description: 队伍不存在
      500:
        description: 服务器错误
    """
    try:
        data = request.json
        if 'score' not in data:
            return jsonify({'error': '缺少分数数据'}), 400
        group = GroupInfo.query.get(team_id)
        if not group:
            return jsonify({'error': '队伍不存在'}), 404
        group.count = data['score']
        db.session.commit()
        return jsonify({'success': True})
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500

@app.route('/api/team-members')
def get_team_members():
    members = TeamMember.query.all()
    print(f"Debug: 查询到{len(members)}个团队成员")
    result = [{
        'id': m.id,
        'name': m.name,
        'photo': f'/static/images/{m.id}.jpg',
        'responsibility': m.responsibility,
        'introduction': m.introduction
    } for m in members]
    return jsonify(result)

# 游戏页面路由
@app.route('/game')
@login_required
def game():
    return render_template('game.html')

# 游戏加载路由
@app.route('/game/<game_name>')
@login_required
def play_game(game_name):
    return render_template(f'{game_name}.html')

# 游戏列表API
@app.route('/api/games')
def get_games():
    games = [
            {
                'name': '贪吃蛇',
                'image': 'snake.jpg',
                'path': 'snake_game'
            },
            {
                'name': '俄罗斯方块',
                'image': 'tetris.jpg',
                'path': 'tetris_game'
            }
        ]
    return jsonify(games)

# 游戏文件加载API
@app.route('/api/game/<path:game_path>/files')
def get_game_files(game_path):
    # 安全验证：防止路径遍历攻击
    if '..' in game_path or os.path.isabs(game_path):
        print(f'恶意路径尝试: {game_path}')
        return jsonify({'error': '无效的游戏路径'}), 400
    
    game_dir = os.path.join(app.root_path, game_path)
    print(f'尝试加载游戏目录: {game_dir}')
    
    if not os.path.exists(game_dir):
        print(f'游戏目录不存在: {game_dir}')
        return jsonify({'error': '游戏目录不存在'}), 404
    
    if not os.path.isdir(game_dir):
        print(f'路径不是目录: {game_dir}')
        return jsonify({'error': '无效的游戏目录'}), 400
    
    try:
        files = {
            'html': '',
            'css': '',
            'js': ''
        }
        
        # 读取HTML文件
        html_path = os.path.join(game_dir, 'index.html')
        if os.path.exists(html_path):
            with open(html_path, 'r', encoding='utf-8') as f:
                files['html'] = f.read()
            print(f'成功读取HTML文件: {html_path}')
        else:
            print(f'HTML文件不存在: {html_path}')
            return jsonify({'error': '缺少游戏主HTML文件'}), 404
        
        def read_files_from_directory(base_dir, file_ext, default_filename=None):
            """从目录中读取指定扩展名的文件"""
            files_content = []
            if os.path.exists(base_dir):
                for filename in os.listdir(base_dir):
                    if filename.endswith(file_ext):
                        file_path = os.path.join(base_dir, filename)
                        try:
                            with open(file_path, 'r', encoding='utf-8') as f:
                                content = f.read()
                                files_content.append(content)
                            print(f'成功读取文件: {file_path}')
                        except Exception as e:
                            print(f'读取文件失败 {file_path}: {e}')
            return '\n'.join(files_content)
        
        # 读取CSS文件
        css_dir = os.path.join(game_dir, 'css')
        files['css'] = read_files_from_directory(css_dir, '.css')
        
        # 读取JS文件
        js_dir = os.path.join(game_dir, 'js')
        files['js'] = read_files_from_directory(js_dir, '.js')
        
        return jsonify(files)
        
    except Exception as e:
        print(f'加载游戏文件时出错: {e}')
        return jsonify({'error': f'加载游戏文件失败: {str(e)}'}), 500

# 运行应用
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)


@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    处理用户登录请求
    GET: 显示登录页面
    POST: 验证用户凭据并创建会话
    """
    # 清除之前的闪存消息
    session.pop('_flashes', None)
    
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        
        # 验证输入
        if not username or not password:
            flash('请填写所有字段', 'danger')
        elif database.check_user(username, password):
            # 验证成功，创建会话
            session['username'] = username
            flash('登录成功', 'success')
            return redirect(url_for('index'))
        else:
            flash('用户名或密码错误', 'danger')
    
    # 显示登录页面
    return render_template('login.html', form=form)